﻿using System.Linq;
using System.Modules.Contracts.DTO;
using System.Modules.SharePoint.Contracts.Attributes;
using System.Modules.SharePoint.ExceptionHanlding;
using System.Reflection;
using Microsoft.Office.Server.UserProfiles;

namespace System.Modules.SharePoint.Extensions
{
    /// <summary>
    /// User Profile Extensions
    /// </summary>
    public static class UserProfileExtensions
    {
        /// <summary>
        /// This method Loads user profile into an object of type T
        /// </summary>
        /// <param name="item">UserProfile</param>
        /// <param name="corePropertyManager">CorePropertyManager</param>
        /// <typeparam name="T"></typeparam>
        /// <returns>object of type T</returns>
        public static T LoadUserProfile<T>(this UserProfile item, CorePropertyManager corePropertyManager) where T : new()
        {
            var value = new T();
            Type type = typeof (T);
            PropertyInfo[] properties = type.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                var bindingProperty = property.GetCustomAttributes(typeof (MappingSPCoreProperty), false).FirstOrDefault() as MappingSPCoreProperty;
                string propertyName = bindingProperty != null && !String.IsNullOrEmpty(bindingProperty.Name) ? bindingProperty.Name : property.Name;
                CoreProperty coreProperty = corePropertyManager.GetPropertyByName(propertyName);
                if (property.CanWrite && coreProperty != null)
                {
                    UserProfileValueCollection fieldValue = item[propertyName];
                    if (bindingProperty != null && bindingProperty.Function != null)
                    {
                        fieldValue = bindingProperty.Function.Invoke(fieldValue) as UserProfileValueCollection;
                    }
                    if (fieldValue != null && fieldValue.Value != null)
                    {
                        if (fieldValue.Value.GetType() == property.PropertyType)
                        {
                            property.SetValue(value, fieldValue.Value, null);
                        }
                        else if (property.PropertyType.IsGenericType && property.PropertyType.IsSubclassOf(typeof (Updatable)))
                        {
                            var updatable = Activator.CreateInstance(property.PropertyType) as Updatable;
                            if (updatable != null)
                            {
                                updatable.SetValue(Convert.ChangeType(fieldValue.Value, updatable.GetUnderlyingType()));
                                property.SetValue(value, updatable, null);
                            }
                        }
                        else
                        {
                            property.SetValue(value, Convert.ChangeType(fieldValue.Value, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType), null);
                        }
                        //property.SetValue(value, fieldValue.GetType() == property.PropertyType ? fieldValue : Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType), null);
                    }
                }
            }
            return value;
        }

        /// <summary>
        /// This method Loads user profile into an object of type T
        /// </summary>
        /// <param name="item">UserProfile</param>
        /// <typeparam name="T"></typeparam>
        /// <returns>object of type T</returns>
        public static T LoadUserProfile<T>(this UserProfile item) where T : new()
        {
            var value = new T();
            Type type = typeof (T);
            PropertyInfo[] properties = type.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                var bindingProperty = property.GetCustomAttributes(typeof (MappingSPCoreProperty), false).FirstOrDefault() as MappingSPCoreProperty;
                string propertyName = bindingProperty != null && !String.IsNullOrEmpty(bindingProperty.Name) ? bindingProperty.Name : property.Name;
                if (property.CanWrite)
                {
                    UserProfileValueCollection fieldValue = null;
                    try
                    {
                        fieldValue = item[propertyName];
                    }
                    catch (Exception exception)
                    {
                        exception.Handle();
                    }
                    finally
                    {
                        if (bindingProperty != null && bindingProperty.Function != null)
                        {
                            fieldValue = bindingProperty.Function.Invoke(fieldValue) as UserProfileValueCollection;
                        }
                        if (fieldValue != null && fieldValue.Value != null)
                        {
                            if (fieldValue.Value.GetType() == property.PropertyType)
                            {
                                property.SetValue(value, fieldValue.Value, null);
                            }
                            else if (property.PropertyType.IsGenericType && property.PropertyType.IsSubclassOf(typeof (Updatable)))
                            {
                                var updatable = Activator.CreateInstance(property.PropertyType) as Updatable;
                                if (updatable != null)
                                {
                                    updatable.SetValue(Convert.ChangeType(fieldValue.Value, updatable.GetUnderlyingType()));
                                    property.SetValue(value, updatable, null);
                                }
                            }
                            else
                            {
                                property.SetValue(value, Convert.ChangeType(fieldValue.Value, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType), null);
                            }
                            //property.SetValue(value, fieldValue.GetType() == property.PropertyType ? fieldValue : Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType), null);
                        }
                    }
                }
            }
            return value;
        }
    }
}